﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using RazorBridge.Helpers;

namespace RazorBridge.Mvc
{
    /// <summary>
    /// E3Retail's custom view, extends razor view
    /// </summary>
    public class CompositeRazorEngine : RazorViewEngine
    {
        public CompositeRazorEngine()
        {
            this.RegisterRazorFormats();
        }

        /// <summary>
        /// find a view from directory or assembly
        /// </summary>
        /// <param name="controllerContext">controller class</param>
        /// <param name="viewName">name for view to find</param>
        /// <param name="masterName">master page file name</param>
        /// <param name="useCache">flag to cache view</param>
        /// <returns>Returns ViewEngineResult if found; NULL if view dosen't exists in file or assembly</returns>
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            return NewFindView(controllerContext, viewName, masterName, useCache);
        }

        /// <summary>
        /// find a view from directory or assembly
        /// </summary>
        /// <param name="controllerContext">controller</param>
        /// <param name="viewName">name for view to find</param>
        /// <param name="masterName">master page file name</param>
        /// <param name="useCache">flag to cache view</param>
        /// <returns>Returns ViewEngineResult if found; NULL if view dosen't exists in file or assembly</returns>
        private ViewEngineResult NewFindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {            // Get the name of the controller from the path 
            string area = "";
            if (controllerContext.RouteData.DataTokens.ContainsKey("area"))
            {
                area = controllerContext.RouteData.DataTokens["area"].ToString();
            }
            if (useCache)
            {               //If using the cache, check to see if the location is cached.

                string cacheLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, viewName);
                if (!string.IsNullOrWhiteSpace(cacheLocation))
                {
                    return new ViewEngineResult(CreateView(controllerContext, cacheLocation, masterName), this);
                }
            }

            string[] locationFormats = string.IsNullOrEmpty(area) ? ViewLocationFormats : AreaViewLocationFormats;             // for each of the paths defined, format the string and see if that path exists. When found, cache it.   

            string currentPath = FrameworkConfigurationFactory.CurrentInstance.GetViewFilePath(viewName);
            if (!string.IsNullOrEmpty(currentPath) && FileExists(controllerContext, currentPath))
            {
                ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, viewName, currentPath);
                return new ViewEngineResult(CreateView(controllerContext, currentPath, masterName), this);
            }

            return new ViewEngineResult(locationFormats.Distinct().ToList());
        }

        /// <summary>
        /// find partial view from directory or assembly
        /// </summary>
        /// <param name="controllerContext">Controller</param>
        /// <param name="partialViewName">name for partial view</param>
        /// <param name="useCache">flag to cache partial views</param>
        /// <returns>Returns ViewEngineResult if found; NULL if partial view dosen't exists in file or assembly</returns>
        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (!string.IsNullOrEmpty(partialViewName) && partialViewName.Contains("EditorTemplates"))
            {
                string[] parts = partialViewName.Split(Convert.ToChar(Constants.PATH_SEPARATOR, CultureInfo.InvariantCulture));
                if (parts != null && parts.Length == 3)
                {
                    partialViewName = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", parts[1], Constants.PATH_SEPARATOR, parts[2]);
                }
            }
            if (useCache)
            {               //If using the cache, check to see if the location is cached.

                string cacheLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, partialViewName);
                if (!string.IsNullOrWhiteSpace(cacheLocation))
                {
                    return new ViewEngineResult(CreatePartialView(controllerContext, cacheLocation), this);
                }
            }

            string currentPath = FrameworkConfigurationFactory.CurrentInstance.GetPartialViewFilePath(partialViewName);
            if (!string.IsNullOrWhiteSpace(currentPath) && FileExists(controllerContext, currentPath))
            {
                ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, partialViewName, currentPath);
                return new ViewEngineResult(CreatePartialView(controllerContext, currentPath), this);
            }
            return new ViewEngineResult(PartialViewLocationFormats.Distinct().ToList());

        }

        
        #region  "Private Utility Method"

        /// <summary>
        /// Register Formats for views and partial views location, only related to CSharp development
        /// </summary>
        private void RegisterRazorFormats()
        {
            if (this.FileExtensions != null && this.FileExtensions.Length > 0)
            {
                var filteredFileextensions = this.FileExtensions.Where(extension => extension.IndexOf(Constants.CSHARP_FILE_EXTENTION, StringComparison.OrdinalIgnoreCase) > -1);
                if (filteredFileextensions != null)
                {
                    this.FileExtensions = filteredFileextensions.ToArray();
                }
            }

            if (this.ViewLocationFormats != null && this.ViewLocationFormats.Length > 0)
            {
                var filteredViewLocationFormats = this.ViewLocationFormats.Where(format => format.IndexOf(Constants.CSHARP_FILE_EXTENTION, StringComparison.OrdinalIgnoreCase) > -1);
                if (filteredViewLocationFormats != null)
                {
                    this.ViewLocationFormats = filteredViewLocationFormats.ToArray();
                }
            }

            if (this.PartialViewLocationFormats != null && this.PartialViewLocationFormats.Length > 0)
            {
                var filteredPartialViewLocationFormats = this.PartialViewLocationFormats.Where(format => format.IndexOf(Constants.CSHARP_FILE_EXTENTION, StringComparison.OrdinalIgnoreCase) > -1);
                if (filteredPartialViewLocationFormats != null)
                {
                    this.PartialViewLocationFormats = filteredPartialViewLocationFormats.ToArray();
                }
            }

        }

        #endregion
    }
}
